
package gameoflife;

/**
 * Welcome to the Game of Life class.
 *
 * A Game of Life object is designed to hold all the params for simulation
 * and execute the required simulation by creating a new Simulator object.
 * @author CJ
 */
public class GameOfLife {

    //Instance Variables
    private SimulationParams simulationParams;

    //Constructors
    /**
     * Basic constructor of the Game of Life object.
     *
     * @param args, command line arguments
     * @throws GameOfLifeIllegalArgumentException, if command line arguments are non-valid
     */
    public GameOfLife(String[] args) throws GameOfLifeIllegalArgumentException{
        parseArgs(args);
    }

    //Public methods
    /**
     * Driver method that drives a new simulation based on the number of generations
     * and updaterules this object was constructed with.
     */
    public void runSimulation() {
        try{
            int generationSize = this.simulationParams.getGenerationSize();
            int simulationsToBeDone = this.simulationParams.getSimulationLength();
            UpdateRules updateRules = this.simulationParams.getUpdateRules();
                    
            Simulator sim = new Simulator(updateRules, generationSize);
            System.out.println(sim.getGenerationString());
            for(int i = 0; i < simulationsToBeDone; ++i){
                sim.simulate();
                System.out.println(sim.getGenerationString());
            }
        }catch(SimulationErrorException e){
            System.out.println(e.getMessage());
        }catch(Exception e){
            System.out.println(e.getMessage());
        }
    }


    //Private methods
    /**
     *  Main logic that places the args into updateRules instance variable.
     *
     * @param args, command line arguments
     * @throws GameOfLifeIllegalArgumentException, if command lines arguments are non-valid
     */
    private void parseArgs(String[] args) throws GameOfLifeIllegalArgumentException{
        //SanityCheck
        int[] commandInput = sanityCheckArgs(args);

        //Now parse the actual input.
        int generationSize = commandInput[0];
        int simulationLength = commandInput[1];
        UpdateRules updateRules = new UpdateRules(commandInput[2], commandInput[3], commandInput[4], commandInput[5]);

        //Set to the params object
        this.simulationParams = new SimulationParams(generationSize, simulationLength, updateRules);
    }

    /**
     * Main logic that detects incorrect input is enclosed below.
     *
     * @param args, the command line arguments
     * @throws GameOfLifeIllegalArgumentException, thrown if incorrect input is detected.
     * @return commandInputs, a readable array of the commands in integer form
     */
    private int[] sanityCheckArgs(String[] args) throws GameOfLifeIllegalArgumentException{
        //Check length
        if(args.length != 6){
            throw new GameOfLifeIllegalArgumentException("Whoops! 6 arguments were not passed.");
        }

        //Check all valid numbers
        int[] commandInput = new int[args.length];
        for(int i = 0; i < args.length; ++i){
            try{
                commandInput[i] = Integer.parseInt(args[i]);
            }catch(Exception e){
                throw new GameOfLifeIllegalArgumentException("Whoops! One argument was not a parsable integer.");
            }
        }

        //Check if numbers are within the correct values
        for(int i = 0; i < commandInput.length; ++i){
            if(commandInput[i] < 0){
                throw new GameOfLifeIllegalArgumentException("Whoops! One argument was negative.");
            }
        }

        //Check specifics

        //Check generation size
        if(commandInput[0] < 1){
            throw new GameOfLifeIllegalArgumentException("Whoops! Generation size must be at least one.");
        }

        //Check simulation length
        if(commandInput[1] < 1){
            throw new GameOfLifeIllegalArgumentException("Whoops! Simulation length must be at least one.");
        }

        //Check updateRules
        for(int i = 2; i < commandInput.length; ++i){
            if(commandInput[i] > 1){
                throw new GameOfLifeIllegalArgumentException("Whoops! An update rule had a result greater than one.");
            }
        }

        return commandInput;
    }

}
